package io.itit.ecp.admin.provide.action.controller.miniprogram;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.provide.action.req.WarningReq;
import io.itit.ecp.admin.provide.action.resp.miniprogram.WarningDetailResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.WarningResp;
import io.itit.ecp.admin.provide.helper.SceneHelper;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.entity.extend.EnergyDataExtEntity;
import io.itit.ecp.admin.server.entity.extend.UserWarningExtEntity;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.utils.ParamUtils;
import io.itit.grass.web.wall.utils.PageUtils;
import io.itit.grass.web.wall.utils.ShiroUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 消息提醒
 */
@Api(tags = "消息提醒")
@RestController
@RequestMapping("/mini/warning")
public class MiniWarningController {

    @Resource
    private IEarlyWarningPushService earlyWarningPushService;

    @Resource
    private IDeviceWarningPushUserService deviceWarningPushUserService;

    @Resource
    private IDeviceWarningRecordService deviceWarningRecordService;

    @Resource
    private IMeterDeviceService meterDeviceService;

    @Resource
    private IPhysicalModelService physicalModelService;

    @Resource
    private IEnergyConsumptionTypeService energyConsumptionTypeService;

    @Resource
    private ISceneProjectService sceneProjectService;

    @Resource
    private IEarlyWarningRecordService earlyWarningRecordService;

    /**
     * 消息提醒-列表查询
     *
     * @param req req
     */
    @ApiOperation("消息提醒-列表查询")
    @PostMapping("list")
    public ResultResp<IPage<WarningResp>> warningList(@RequestBody WarningReq req) {
        if (!StringUtils.hasLength(req.getWarningType())) {
            return unionWarningList(req);
        } else if ("3".equals(req.getWarningType())) { // 动态
            return deviceWarningList(req);
        }
        return earlyWarningList(req);
    }

    private ResultResp<IPage<WarningResp>> unionWarningList(WarningReq req) {
        IPage<UserWarningExtEntity> page = earlyWarningPushService.unionWarningPage(ParamUtils.paramDto(req)
                        .add("userId", ShiroUtils.getUserId()),
                PageUtils.getPage(req, EnergyDataExtEntity.class));
        List<WarningResp> warningResps = new ArrayList<>(page.getRecords().size());
        Set<String> sceneProjectIds = page.getRecords().stream().map(UserWarningExtEntity::getSceneProjectId).collect(Collectors.toSet());
        Map<String, SceneProjectEntity> projectEntityMap = sceneProjectIds.isEmpty() ? Collections.emptyMap() : sceneProjectService.listByIds(sceneProjectIds)
                .stream().collect(Collectors.toMap(SceneProjectEntity::getId, Function.identity()));
        for (UserWarningExtEntity record : page.getRecords()) {
            String meterDeviceId = record.getMeterDeviceId();
            String deviceDetails;
            List<Map<String, Object>> details = new ArrayList<>();
            if (!"3".equals(record.getWarningType()) && StringUtils.hasLength(meterDeviceId)) {
                MeterDeviceEntity meterDeviceEntity = meterDeviceService.getById(meterDeviceId);
                if (Objects.nonNull(meterDeviceEntity)) {
                    Map<String, Object> m = new HashMap<>();
                    m.put("deviceId", meterDeviceEntity.getId());
                    m.put("deviceName", meterDeviceEntity.getDeviceName());
                    m.put("thresholdValue", formatValue(record.getThresholdValue()));
                    m.put("energyTypeId", meterDeviceEntity.getEnergyTypeId());
                    EnergyConsumptionTypeEntity consumptionTypeEntity = energyConsumptionTypeService.getById(meterDeviceEntity.getEnergyTypeId());
                    m.put("energyTypeName", Objects.isNull(consumptionTypeEntity) ? "" : consumptionTypeEntity.getEnergyName());
                    details.add(m);
                }
                deviceDetails = JSON.toJSONString(details);
            } else {
                deviceDetails = record.getDeviceDetails();
            }
            warningResps.add(new WarningResp()
                    .setId(record.getId())
                    .setWarningName(record.getWarningName())
                    .setSceneProjectId(record.getSceneProjectId())
                    .setSceneEdificeId(record.getSceneEdificeId())
                    .setSceneFloorId(record.getSceneFloorId())
                    .setSceneRoomId(record.getSceneRoomId())
                    .setWarningDate(record.getWarningDate())
                    .setThresholdLevel(record.getThresholdLevel())
                    .setWarningType(record.getWarningType())
                    .setMeterValue(record.getMeterValue())
                    .setStatus(record.getStatus())
                    .setDeviceDetails(deviceDetails)
                    .setReadTime(record.getReadTime())
                    .setSceneProjectName(projectEntityMap.get(record.getSceneProjectId()) == null ? null : projectEntityMap.get(record.getSceneProjectId()).getProjectName())
            );
        }
        Page<WarningResp> resultPage = new Page<>();
        resultPage.setTotal(page.getTotal());
        resultPage.setCurrent(page.getCurrent());
        resultPage.setSize(page.getSize());
        resultPage.setPages(page.getPages());
        resultPage.setRecords(SceneHelper.i().setSceneInfo(warningResps));
        return ResultResp.success(resultPage);
    }

    private Object formatValue(String value) {
        try {
            return new BigDecimal(value).setScale(2, RoundingMode.HALF_UP);
        } catch (NumberFormatException e) {
            return value;
        }
    }

    private ResultResp<IPage<WarningResp>> deviceWarningList(WarningReq req) {
        String userId = ShiroUtils.getUserId();
        if (!StringUtils.hasLength(userId)) {
            return ResultResp.success(new PageDTO<>());
        }
        IPage<WarningResp> page = Joins.of(DeviceWarningPushUserEntity.class)
                .select(DeviceWarningPushUserEntity::getId, DeviceWarningPushUserEntity::getStatus, DeviceWarningPushUserEntity::getReadDate)
                .eq(DeviceWarningPushUserEntity::getUserId, userId)
                .eq(StringUtils.hasLength(req.getStatus()), DeviceWarningPushUserEntity::getStatus, req.getStatus())
                .innerJoin(DeviceWarningRecordEntity.class, DeviceWarningRecordEntity::getId, DeviceWarningPushUserEntity::getDeviceWarningRecordId)
                .selectAs(builder -> builder.add(DeviceWarningRecordEntity::getWarningName)
                        .add(DeviceWarningRecordEntity::getSceneProjectId)
                        .add(DeviceWarningRecordEntity::getSceneEdificeId)
                        .add(DeviceWarningRecordEntity::getSceneFloorId)
                        .add(DeviceWarningRecordEntity::getSceneRoomId)
                        .add(DeviceWarningRecordEntity::getThresholdLevel)
                        .add(DeviceWarningRecordEntity::getDeviceDetails)
                        .add(DeviceWarningRecordEntity::getWarningDate))
                .eq(StringUtils.hasLength(req.getSceneProjectId()), DeviceWarningRecordEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.hasLength(req.getSceneEdificeId()), DeviceWarningRecordEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.hasLength(req.getSceneFloorId()), DeviceWarningRecordEntity::getSceneFloorId, req.getSceneFloorId())
                .end()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, DeviceWarningRecordEntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, WarningResp::getSceneProjectName)
                .end()
                .joinPage(PageUtils.getPage(req, WarningResp.class), WarningResp.class);
        return ResultResp.success(SceneHelper.i().setSceneInfo(page));
    }

    private ResultResp<IPage<WarningResp>> earlyWarningList(WarningReq req) {
        String userId = ShiroUtils.getUserId();
        if (!StringUtils.hasLength(userId)) {
            return ResultResp.success(new PageDTO<>());
        }
        IPage<WarningResp> page = Joins.of(EarlyWarningPushEntity.class)
                .select(EarlyWarningPushEntity::getId, EarlyWarningPushEntity::getStatus, EarlyWarningPushEntity::getReadTime)
                .eq(EarlyWarningPushEntity::getUserId, userId)
                .eq(StringUtils.hasLength(req.getStatus()), EarlyWarningPushEntity::getStatus, req.getStatus())
                .innerJoin(EarlyWarningRecordEntity.class, EarlyWarningRecordEntity::getId, EarlyWarningPushEntity::getEarlyWarningRecordId)
                .selectAs(builder -> builder.add(EarlyWarningRecordEntity::getWarningName)
                        .add(EarlyWarningRecordEntity::getWarningType)
                        .add(EarlyWarningRecordEntity::getThresholdLevel)
                        .add(EarlyWarningRecordEntity::getSceneProjectId)
                        .add(EarlyWarningRecordEntity::getSceneEdificeId)
                        .add(EarlyWarningRecordEntity::getSceneFloorId)
                        .add(EarlyWarningRecordEntity::getSceneRoomId)
                        .add(EarlyWarningRecordEntity::getMeterDeviceId, "deviceDetails")
                        .add(EarlyWarningRecordEntity::getMeterCondition)
                        .add(EarlyWarningRecordEntity::getPushRule)
                        .add(EarlyWarningRecordEntity::getJudgeRule)
                        .add(EarlyWarningRecordEntity::getMeterValue)
                        .add(EarlyWarningRecordEntity::getThresholdValue)
                        .add(EarlyWarningRecordEntity::getCreateTm, "warningDate"))
                .eq(StringUtils.hasLength(req.getSceneProjectId()), EarlyWarningRecordEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.hasLength(req.getSceneEdificeId()), EarlyWarningRecordEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.hasLength(req.getSceneFloorId()), EarlyWarningRecordEntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.hasLength(req.getSceneCompanyId()), EarlyWarningRecordEntity::getSceneCompanyId, req.getSceneCompanyId())
                .eq(StringUtils.hasLength(req.getWarningType()), EarlyWarningRecordEntity::getWarningType, req.getWarningType())
                .eq(StringUtils.hasLength(req.getThresholdLevel()), EarlyWarningRecordEntity::getThresholdLevel, req.getThresholdLevel())
                .end()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, EarlyWarningRecordEntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, WarningResp::getSceneProjectName)
                .end()
                .joinPage(PageUtils.getPage(req, WarningResp.class), WarningResp.class);
        for (WarningResp record : page.getRecords()) {
            String meterDeviceId = record.getDeviceDetails();
            String deviceDetails = null;
            List<Map<String, Object>> details = new ArrayList<>();
            if (StringUtils.hasLength(meterDeviceId)) {
                MeterDeviceEntity meterDeviceEntity = meterDeviceService.getById(meterDeviceId);
                if (Objects.nonNull(meterDeviceEntity)) {
                    Map<String, Object> m = new HashMap<>();
                    m.put("deviceId", meterDeviceEntity.getId());
                    m.put("deviceName", meterDeviceEntity.getDeviceName());
                    m.put("thresholdValue", Objects.isNull(record.getThresholdValue()) ? BigDecimal.ZERO : record.getThresholdValue().setScale(2, RoundingMode.HALF_UP));
                    m.put("energyTypeId", meterDeviceEntity.getEnergyTypeId());
                    EnergyConsumptionTypeEntity consumptionTypeEntity = energyConsumptionTypeService.getById(meterDeviceEntity.getEnergyTypeId());
                    m.put("energyTypeName", Objects.isNull(consumptionTypeEntity) ? "" : consumptionTypeEntity.getEnergyName());
                    details.add(m);
                }
                deviceDetails = JSON.toJSONString(details);
            }
            record.setDeviceDetails(deviceDetails);
        }
        return ResultResp.success(SceneHelper.i().setSceneInfo(page));
    }

    /**
     * 消息提醒-详情
     */
    @ApiOperation("消息提醒-详情")
    @GetMapping("detail")
    public ResultResp<WarningDetailResp> detail(@RequestParam String id) {
        WarningDetailResp detailResp = null;
        EarlyWarningPushEntity warningPushEntity = earlyWarningPushService.readById(id);
        if (Objects.nonNull(warningPushEntity)) {
            detailResp = new WarningDetailResp();
            detailResp.setId(id);
            detailResp.setReadTime(warningPushEntity.getReadTime())
                    .setStatus(warningPushEntity.getStatus());
            EarlyWarningRecordEntity recordEntity = earlyWarningRecordService.getById(warningPushEntity.getEarlyWarningRecordId());
            MeterDeviceEntity meterDeviceEntity = null;
            String meterDeviceId = null;
            if (Objects.nonNull(recordEntity)) {
                SceneProjectEntity projectEntity = sceneProjectService.getById(recordEntity.getSceneProjectId());
                meterDeviceId = recordEntity.getMeterDeviceId();
                detailResp.setWarningName(recordEntity.getWarningName())
                        .setThresholdLevel(recordEntity.getThresholdLevel())
                        .setSceneProjectId(recordEntity.getSceneProjectId())
                        .setSceneEdificeId(recordEntity.getSceneEdificeId())
                        .setSceneFloorId(recordEntity.getSceneFloorId())
                        .setSceneRoomId(recordEntity.getSceneRoomId())
                        .setMeterCondition(recordEntity.getMeterCondition())
                        .setPushRule(recordEntity.getPushRule())
                        .setJudgeRule(recordEntity.getJudgeRule())
                        .setMeterValue(recordEntity.getMeterValue())
                        .setWarningType(recordEntity.getWarningType())
                        .setThresholdValue(recordEntity.getThresholdValue())
                        .setWarningDate(recordEntity.getCreateTm())
                        .setSceneProjectName(Objects.isNull(projectEntity) ? null : projectEntity.getProjectName());

                meterDeviceEntity = meterDeviceService.getById(recordEntity.getMeterDeviceId());
            }
            WarningDetailResp.WarningDeviceInfo warningDeviceInfo = new WarningDetailResp.WarningDeviceInfo()
                    .setMeterDeviceId(meterDeviceId)
                    .setValue(recordEntity.getMeterValue());
            if (Objects.nonNull(meterDeviceEntity) && StringUtils.hasLength(meterDeviceEntity.getModelId())) {
                PhysicalModelEntity modelEntity = physicalModelService.getById(meterDeviceEntity.getModelId());
                warningDeviceInfo.setParamName(Objects.isNull(modelEntity) ? null : modelEntity.getModelName());
            }
            if (Objects.nonNull(meterDeviceEntity)) {
                warningDeviceInfo.setDeviceName(meterDeviceEntity.getDeviceName());
                EnergyConsumptionTypeEntity consumptionTypeEntity = energyConsumptionTypeService.getById(meterDeviceEntity.getEnergyTypeId());
                warningDeviceInfo.setEnergyTypeName(Objects.isNull(consumptionTypeEntity) ? null : consumptionTypeEntity.getEnergyName());
            }
            detailResp.setDeviceInfos(Collections.singletonList(warningDeviceInfo));
            return ResultResp.success(SceneHelper.i().setSceneInfo(Collections.singletonList(detailResp)).get(0));
        } else {
            DeviceWarningPushUserEntity pushUserEntity = deviceWarningPushUserService.readById(id);
            if (Objects.nonNull(pushUserEntity)) {
                detailResp = new WarningDetailResp();
                detailResp.setId(id);
                detailResp.setReadTime(pushUserEntity.getReadDate())
                        .setStatus(pushUserEntity.getStatus());
                DeviceWarningRecordEntity recordEntity = deviceWarningRecordService.getById(pushUserEntity.getDeviceWarningRecordId());
                SceneProjectEntity projectEntity = sceneProjectService.getById(recordEntity.getSceneProjectId());
                List<DeviceWarningRecordEntity.DeviceDetail> deviceDetails = JSON.parseArray(recordEntity.getDeviceDetails(), DeviceWarningRecordEntity.DeviceDetail.class);
                detailResp.setDeviceDetails(recordEntity.getDeviceDetails())
                        .setWarningName(recordEntity.getWarningName())
                        .setThresholdLevel(recordEntity.getThresholdLevel())
                        .setSceneProjectId(recordEntity.getSceneProjectId())
                        .setSceneEdificeId(recordEntity.getSceneEdificeId())
                        .setSceneFloorId(recordEntity.getSceneFloorId())
                        .setSceneRoomId(recordEntity.getSceneRoomId())
                        .setJudgeRule(recordEntity.getJudgeRule())
                        .setWarningType("3")
                        .setWarningDate(recordEntity.getWarningDate())
                        .setSceneProjectName(Objects.isNull(projectEntity) ? null : projectEntity.getProjectName());
                detailResp.setDeviceInfos(Objects.isNull(deviceDetails) ? Collections.emptyList() :
                        deviceDetails.stream().map(item -> new WarningDetailResp.WarningDeviceInfo()
                                .setMeterDeviceId(item.getDeviceId())
                                .setDeviceName(item.getDeviceName())
                                .setValue(item.getThresholdValue())
                                .setParamName(item.getModelName())).collect(Collectors.toList()));
            }
        }
        return ResultResp.success(SceneHelper.i().setSceneInfo(Collections.singletonList(detailResp)).get(0));
    }

    /**
     * 消息提醒-批量已读
     *
     * @param type 消息类型(1:计量,2:碳排放,3:动态)
     */
    @ApiOperation("消息提醒-批量已读")
    @PostMapping("batchRead")
    public ResultResp<Void> batchRead(@RequestParam(required = false) String type) {
        String userId = ShiroUtils.getUserId();
        if ("3".equals(type)) {
            batchReadDeviceWarning(userId);
        } else if ("1".equals(type) || "2".equals(type)) {
            batchReadEarlyWarning(userId, type);
        } else if (!StringUtils.hasLength(type)) {
            batchReadDeviceWarning(userId);
            batchReadEarlyWarning(userId, type);
        }
        return ResultResp.success();
    }

    private void batchReadEarlyWarning(String userId, String type) {
        earlyWarningPushService.batchRead(userId, type);
    }

    private void batchReadDeviceWarning(String userId) {
        deviceWarningPushUserService.batchReadByUserId(userId);
    }

}
